package com.yuyou.hxyy.service.api.service.impl;

import com.alibaba.fastjson.JSON;
import com.yuyou.hxyy.service.api.Async.AsyncService;
import com.yuyou.hxyy.service.api.bean.Pagination;
import com.yuyou.hxyy.service.api.entity.*;
import com.yuyou.hxyy.service.api.enums.CategoryEnum;
import com.yuyou.hxyy.service.api.enums.CommEnums;
import com.yuyou.hxyy.service.api.exception.BusinessException;
import com.yuyou.hxyy.service.api.mapper.DataImportMapper;
import com.yuyou.hxyy.service.api.mapper.WordMapper;
import com.yuyou.hxyy.service.api.service.IWordRepoService;
import com.yuyou.hxyy.service.api.service.IWordService;
import com.yuyou.hxyy.service.api.service.IWordUnitService;
import com.yuyou.hxyy.service.api.service.IWordUrlService;
import com.yuyou.hxyy.service.api.util.DateUtil;
import com.yuyou.hxyy.service.api.util.DefindBeanUtils;
import com.yuyou.hxyy.service.api.util.Sequence;
import com.yuyou.hxyy.service.api.vo.req.WordExcel;
import com.yuyou.hxyy.service.api.vo.resp.WordVo;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
public class WordServiceImpl implements IWordService {

    @Autowired
    private WordMapper mapper;

    @Autowired
    private DataImportMapper dataImportMapper;

    @Autowired
    private IWordUnitService wordUnitService;

    @Autowired
    private IWordRepoService wordRepoService;

    @Autowired
    private IWordUrlService wordUrlService;

    @Autowired
    private AsyncService asyncService;

    @Override
    public int deleteByPrimaryKey(Long wordId) {
        return mapper.deleteByPrimaryKey(wordId);
    }

    @Override
    public int insert(Word record) {
        return mapper.insert(record);
    }

    @Override
    public Word selectByPrimaryKey(Long wordId) {
        return mapper.selectByPrimaryKey(wordId);
    }

    @Override
    public int updateByPrimaryKeySelective(Word record) {
        return mapper.updateByPrimaryKeySelective(record);
    }

    @Override
    @Transactional
    public void insertWord(String en, String voice, String cn, Long wordRepoId, Long wordUnitId, Long userId) {
        WordUnit unit = wordUnitService.selectByPrimaryKey(wordUnitId);
        if(unit == null){
            return;
        }else if(!unit.getWordRepoId().equals(wordRepoId)){
            throw new BusinessException("该关卡不属于该词典，请确认。");
        }

        Word w = new Word();
        Date date = new Date();
        Integer sort = mapper.getMaxSort(wordUnitId);
        w.setWordId(Sequence.getSequence().nextId());
        w.setCreateTime(date);
        w.setUpdateTime(date);
        w.setCreateUser(userId);
        w.setUpdateUser(userId);
        w.setEn(en);
        w.setVoice(voice);
        w.setCn(cn);
        w.setWordRepoId(wordRepoId);
        w.setWordUnitId(wordUnitId);
        w.setIsDel(0);

        if(dealWordUrl(w)){
            w.setStatus(CommEnums.urlStatus.done.getValue());
        }else {
            w.setStatus(CommEnums.urlStatus.init.getValue());
        }

        w.setSort(sort == null ? 0:sort+1);
        insert(w);
    }

    @Override
    @Transactional
    public void updateWord(Long id , String en, String voice, String cn, Long userId) {
        Word old = selectByPrimaryKey(id);
        if(old == null){return;}
        Word other = findByRepoUnitEn(old.getWordRepoId() , old.getWordUnitId() , en);
        if(other != null && !other.getWordId().equals(old.getWordId())){
            throw new BusinessException("该关卡下已存在该单词");
        }
        Word w = new Word();
        w.setWordId(id);
        w.setEn(en);
        w.setVoice(voice);
        w.setCn(cn);
        w.setUpdateTime(new Date());
        w.setUpdateUser(userId);

        WordUrl wordUrl = wordUrlService.findByKey(en.trim());
        if(wordUrl == null){
            if(dealWordUrl(w)){
                w.setStatus(CommEnums.urlStatus.done.getValue());
            }else {
                w.setStatus(CommEnums.urlStatus.init.getValue());
            }
        }else {
            w.setStatus(CommEnums.urlStatus.done.getValue());
        }

        updateByPrimaryKeySelective(w);
    }

    @Override
    public Word findByRepoUnitEn(Long repoId, Long unitId, String en) {
        return mapper.findByRepoUnitEn(repoId,unitId,en);
    }

    @Override
    @Transactional
    public void deleteByIds(String ids) {
        mapper.deleteByIds(ids);
    }

    @Override
    public int findWordCount(Pagination<WordVo> queryPgn) {
        return mapper.findWordCount(queryPgn);
    }

    @Override
    public List<WordVo> findWordPage(Pagination<WordVo> queryPgn) {
        List<WordVo> list = mapper.findWordPage(queryPgn);
        for (WordVo w :
                list) {
            if(w.getCategory() != null){
                switch (w.getCategory()){
                    case 1:
                        w.setCategaryName(CategoryEnum.Category.MIDDLE_SCHOOL.getName());
                        break;
                    case 2:
                        w.setCategaryName(CategoryEnum.Category.HIGH_SCHOOL.getName());
                        break;
                    case 0:
                        w.setCategaryName(CategoryEnum.Category.PRIMARY_SCHOOL.getName());
                        break;
                    default:
                        w.setCategaryName("");
                }
            }
            WordUrl url = wordUrlService.findByKey(w.getEn().trim());
            if(url != null){
                w.setUrl(url.getValue());
            }
        }
        return list;
    }


    @Override
    @Transactional
    public DataImport saveWordImport(List<WordExcel> wordExcelList) {

        int total = wordExcelList.size();
        // 有问题的数据不导入
        List<WordExcel> failWordList = checkWordImport(wordExcelList);
        List<Word> wordList = new ArrayList<>(wordExcelList.size());
        int i = 0;
        for(WordExcel wordExcel : wordExcelList){
            Word word = new Word();
            word.setWordId(Sequence.getSequence().nextId());
            word.setWordUnitId(wordExcel.getWordUnitId());
            word.setWordRepoId(wordExcel.getWordRepoId());
            word.setCn(wordExcel.getCn());
            word.setEn(wordExcel.getEn());
            word.setVoice(wordExcel.getVoice());
            word.setSort(i++);
            word.setIsDel(CommEnums.isDel.no.getValue());
            word.setUpdateTime(DateUtil.now());
            word.setCreateTime(DateUtil.now());
            word.setStatus(CommEnums.urlStatus.init.getValue());
            /*if(dealWordUrl(word)){
                word.setStatus(CommEnums.urlStatus.done.getValue());
            }else {
                word.setStatus(CommEnums.urlStatus.init.getValue());
            }*/

            wordList.add(word);
        }

        // 批量插入关卡
        if(!CollectionUtils.isEmpty(wordList)){
            mapper.batchInsertWord(wordList);
        }

        /** 导入成败记录 */
        DataImport dataImport = new DataImport();
        dataImport.setId(Sequence.getSequence().getNextId());
        dataImport.setTotal(total);
        dataImport.setSuccNum(wordList.size());
        dataImport.setFailNum(failWordList.size());
        dataImport.setStatus(failWordList.size() > 0 ? "1" : "0");
        dataImport.setType(CommEnums.resourceType.word.getValue());
        dataImport.setContent(JSON.toJSONString(failWordList));
        dataImport.setCreateTime(DateUtil.now());
        dataImportMapper.insert(dataImport);

        return dataImport;
    }

    private List<WordExcel> checkWordImport(List<WordExcel> wordExcelList) {
        // 导入失败的单词
        List<WordExcel> failWordList = new ArrayList<>();
        Iterator<WordExcel> iterator = wordExcelList.iterator();
        Set<String> wordUniqueSet = new HashSet<>();
        while (iterator.hasNext()) {
            WordExcel wordExcel = iterator.next();
            WordExcel failWord = new WordExcel();
            DefindBeanUtils.copyProperties(wordExcel, failWord);
            StringBuilder failReason = new StringBuilder();

            if (StringUtils.isEmpty(wordExcel.getEn())) {
                failReason.append(";").append("单词为空");
            } else if (StringUtils.isEmpty(wordExcel.getCn())) {
                failReason.append(";").append("词性释义为空");
            } else if (StringUtils.isEmpty(wordExcel.getWordUnit())) {
                failReason.append(";").append("所属关卡为空");
            } else if (StringUtils.isEmpty(wordExcel.getWordRepo())) {
                failReason.append(";").append("所属词库为空");
            } else if (StringUtils.isEmpty(wordExcel.getCategory())) {
                failReason.append(";").append("所属类别为空");
            }else if(wordUniqueSet.contains(wordExcel.getWordRepo() + wordExcel.getWordUnit() + wordExcel.getEn())){
                failReason.append(";").append("单词重复");
            }

            WordRepo wordRepo = wordRepoService.findByNameCategory(wordExcel.getWordRepo(),
                    ("小学".equals(wordExcel.getCategory()) ? 0 : ("初中".equals(wordExcel.getCategory()) ? 1 : 2)));

            if (null == wordRepo) {
                failReason.append(";").append("词库不存在");
            }else{
                WordUnit wordUnit = wordUnitService.findByNameRepo(wordRepo.getWordRepoId(), wordExcel.getWordUnit());
                if(null == wordUnit){
                    failReason.append(";").append("关卡不存在");
                }else if(null != mapper.findByRepoUnitEn(wordRepo.getWordRepoId(), wordUnit.getWordUnitId(), wordExcel.getEn())){
                    failReason.append(";").append("单词已经存在");
                }else{
                    wordExcel.setWordRepoId(wordRepo.getWordRepoId());
                    wordExcel.setWordUnitId(wordUnit.getWordUnitId());
                }
            }

            // 不符合的，移除不导入
            if (!StringUtils.isEmpty(failReason.toString())) {
                failWord.setFailedReason(failReason.toString().substring(1, failReason.toString().length()));
                failWordList.add(failWord);
                iterator.remove();
            }else{
                wordUniqueSet.add(wordExcel.getWordRepo() + wordExcel.getWordUnit() + wordExcel.getEn());
            }
        }
        return failWordList;
    }

    @Override
    public XSSFWorkbook failedInfoOfWordImport(List<WordExcel> wordExcelList){

        XSSFWorkbook excel = new XSSFWorkbook();

        XSSFSheet sheet = excel.createSheet("导入失败信息");

        XSSFRow firstRow = sheet.createRow(0);

        String[] titles = new String[] { "单词","音标","词性释义","所属关卡","所属词库","所属类别","导入失败原因"};

        for (int i = 0; i < titles.length; i++) {
            XSSFCell cell = firstRow.createCell(i);

            // 失败原因设置为红色
            if(i == titles.length -1){
                XSSFCellStyle cellStyle = excel.createCellStyle();
                cellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
                cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
                cell.setCellStyle(cellStyle);
            }
            cell.setCellValue(titles[i]);
        }

        for (int i = 0; i < wordExcelList.size(); i++ ) {

            WordExcel wordExcel = wordExcelList.get(i);

            XSSFRow row = sheet.createRow(i + 1);

            int c = 0;
            XSSFCell cell = row.createCell(c++);
            cell.setCellValue(wordExcel.getEn());

            cell = row.createCell(c++);
            cell.setCellValue(wordExcel.getVoice());

            cell = row.createCell(c++);
            cell.setCellValue(wordExcel.getCn());

            cell = row.createCell(c++);
            cell.setCellValue(wordExcel.getWordUnit());

            cell = row.createCell(c++);
            cell.setCellValue(wordExcel.getWordRepo());

            cell = row.createCell(c++);
            cell.setCellValue(wordExcel.getCategory());

            cell = row.createCell(c++);
            // 失败原因设置为红色
            XSSFCellStyle cellStyle = excel.createCellStyle();
            cellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
            cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
            cell.setCellStyle(cellStyle);
            cell.setCellValue(wordExcel.getFailedReason());
        }
        return excel;
    }

    @Override
    public boolean dealWordUrl(Word word) {
        WordUrl wordUrl = wordUrlService.findByKey(word.getEn().trim());
        if(wordUrl == null){
            return wordUrlService.addUrl(word.getEn().trim());
        }

        return true;
    }

    @Override
    public void updateByEn(String en) {
        mapper.updateByEn(en);
    }

    @Override
    public void dealWordVideo() {
        List<Word> list = mapper.findAllWordByStatus();
        list.forEach(word -> asyncService.AsynUploadJob(word));
    }
}
